#include "task.hpp"
#include <string>
#include <vector>
#include <sys/types.h>
#include <sys/wait.h>


using namespace std;

class channel
{
    public:
    channel(int wfd, pid_t id,const string& name)
    :_wfd(wfd)
    ,_sub_Process_id(id)
    ,_name(name)
    {}

    int wfd()
    {
        return _wfd;
    }

    pid_t pid()
    {
        return _sub_Process_id;
    }

    string name()
    {
        return _name;
    }

    void Close()
    {
        close(_wfd);
    }

    void PrintDebug()
    {
        cout << "_wfd: " << _wfd<< ",_sub_Process_id: " << _sub_Process_id<< ", _name: " << _name << endl;
    }

    private:
    int _wfd;//写fd
    pid_t _sub_Process_id;//子进程的pid
    string _name;

};



class ProcessPool
{
    public:

    ProcessPool(int num)
      :_process_num(num)
    {}   
    

    //创建进程
    void CreateProcess(work_t work)
    {
        vector<int> fds;
        for(int i = 0;i<_process_num;i++)
        {

            int pipefd[2]{0};
            pipe(pipefd);
            pid_t pid = fork();
            if(pid==0)//子进程
            {
                //需要关闭父进程进程下来的写端，只剩下fd=3
                if(!fds.empty())
                {
                    cout<<"Already Close:";
                    for(auto fd : fds)
                    {
                        close(fd);
                        cout<<fd<<" ";
                    }
                    cout<<endl;
                }
                //r --> 关闭写端
                close(pipefd[1]);
                dup2(pipefd[0],0);
                work();
                exit(0);

            }

            //父进程
            //w --> 关闭读端
            close(pipefd[0]);
            string name = "channel"+ to_string(i);
            _channels.push_back(channel(pipefd[1],pid,name));//用于写的存进去
            
            //把父进程的wfd放进去
            fds.push_back(pipefd[1]);


        }   
    }


    int NextChannel()
    {
        static int next = 0;
        int count = next;
        next++;
        next %= _channels.size();
        _channels[count].PrintDebug();
        return count;
    }

    void SandTask(int channel, int TaskCode)
    {
        //cout<<"I am sanding code:"<< TaskCode<<endl;
        write(_channels[channel].wfd(),&TaskCode,sizeof(TaskCode));
        sleep(1);
    }

    //退出所有子进程
    // void KillAll()
    // {

    //     //通过把channel中的所有的wfd关闭，子进程也全部退出
    //     for(auto& channel : _channels)
    //     {
    //         cout<<"!!"<<endl;
    //         channel.Close();
            
    //         pid_t pid = channel.pid();
    //         cout<<pid<<" ";
    //         cout<<"?"<<endl;
    //         pid_t rid = waitpid(pid,nullptr,0);
    //         cout<<rid<<endl;
    //         cout<<".."<<endl;
    //         if(rid==pid)//等待成功
    //         {
    //             cout<<"Sucess reclaim pid:"<<pid<<endl;
    //         }

    //     }   
    // }    

    void KillAll()
    {
        for (auto &channel : _channels)
        {
            channel.Close();

            pid_t pid = channel.pid();

            pid_t rid = waitpid(pid, nullptr, 0);

            if (rid == pid)
            {
                std::cout << "wait sub process: " << pid << " success..." << std::endl;
            }
        }
    }


    // void Wait()
    // {
    //     for (auto &channel : _channels)
    //     {
            
    //         pid_t pid = channel.pid();
    //         cout<<"??"<<endl;
    //         pid_t rid = waitpid(pid, nullptr, 0);
    //         cout<<rid<<endl;
    //         if (rid == pid)
    //         {
    //             std::cout << "wait sub process: " << pid << " success..." << std::endl;
    //         }
    //     }
    // }


    void Debug()
    {
        for(auto channel : _channels)
        {
            channel.PrintDebug();
        }
    }

    private:
    int _process_num;//子进程个数
    vector <channel> _channels;//用于存放channel

};


void CtrlProcessPool(ProcessPool* ptr, int cnt)
{
    while(cnt--)
    {
        //选择一个进程
        int channel = ptr->NextChannel();

        //选择一个任务
        int code = _NextTask();

        //发送任务
        ptr->SandTask(channel,code);
        sleep(1);
    }
}




int main(int argc, char* argv[])
{

    //如果参数输入并不正确
    if(argc !=2 )
    {
        cout<<"Usage: ./ProcessPool -(count)"<<endl<<"创建count个进程"<<endl;
        return -1;
    }

    int process_num = std::stoi(argv[1]);
    if(process_num<=0)
    {
        cout<<"error process_num"<<endl;
    }

    srand((uint64_t)(nullptr));

    //1.创建进程和管道
    ProcessPool* ptr = new ProcessPool(process_num);
    ptr->CreateProcess(worker);
    //ptr->Debug();

    //2.控制进程池
    CtrlProcessPool(ptr,5);

    //任务完成
    cout<<"Task finish!!!"<<endl;

    //让所有子进程退出
    ptr->KillAll();


    delete ptr;
    return 0;

}